/**
 * Created by Administrator on 2019/5/17/017.
 * 通用工具类
 */
import SMAP_LinkedList from "./../utils/SMAP_LinkedList.js"

const Cesium = DE.__namespace.Cesium

class CZML_GENERALTOOLS_CLASS {
  static CzmlList = new SMAP_LinkedList()
  // 角度显示事件存储Map
  static AngleDisplayEventFunc
  static AngleDisplayEvent = new Map()
  // 位置、姿态数据获取时间存储Map
  static GetPosAttiEventFunc
  static GetPosAttiEventId = new Set()
  static SMAP_JD_MJD_OFFSET = 2400000.5
  static SMAP_SECS_PER_DAY = 86400.0
  static SMAP_SECS_PER_HOUR = 3600.0
  static SMAP_SECS_PER_MINUTE = 60.0
  static CZML_LAYER = undefined // 创建cesium的CZML数据源
  static HEU_StrMonth = {
    Jan: "01",
    Feb: "02",
    Mar: "03",
    Apr: "04",
    May: "05",
    Jun: "06",
    Jul: "07",
    Aug: "08",
    Sep: "09",
    Oct: "10",
    Nov: "11",
    Dec: "12"
  }

  static HEU_StrMonthRev = {
    "01": "Jan",
    "02": "Feb",
    "03": "Mar",
    "04": "Apr",
    "05": "May",
    "06": "Jun",
    "07": "Jul",
    "08": "Aug",
    "09": "Sep",
    10: "Oct",
    11: "Nov",
    12: "Dec"
  }

  static HEU_StrDay = [
    "01",
    "02",
    "03",
    "04",
    "05",
    "06",
    "07",
    "08",
    "09",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15",
    "16",
    "17",
    "18",
    "19",
    "20",
    "21",
    "22",
    "23",
    "24",
    "25",
    "26",
    "27",
    "28",
    "29",
    "30",
    "31"
  ]

  static HEU_ScenarioTime = 0

  /**
   * 信息库中插入模型对象信息
   * @returns {*}
   */
  static InsertModelObjectInformation(id, data, check) {
    // 不检测
    if (check === false) {
      CZML_GENERALTOOLS_CLASS.CzmlList.push(data)
      return true
    }
    // 进行检测
    // 查找对应id
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })
    // 如果存在直接替换
    if (FindNode !== null) {
      FindNode.data(data)
      return false
    } else {
      CZML_GENERALTOOLS_CLASS.CzmlList.push(data)
      return true
    }
  }

  /**
   * 上图
   * @constructor
   */
  static Upper(viewer) {
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === "document"
    })
    if (FindNode !== null) {
      // 判断当前场景时间是否在重新加载后的场景时间内
      const CurTime = Cesium.JulianDate.toIso8601(viewer.clock._currentTime)
      const ScenarioStartTime = CZML_GENERALTOOLS_CLASS.ISO8601ToUtcgTimeTransformation(FindNode.data().clock.interval.split("/")[0])
      const ScenarioEndTime = CZML_GENERALTOOLS_CLASS.ISO8601ToUtcgTimeTransformation(FindNode.data().clock.interval.split("/")[1])
      const diffSec1 = CZML_GENERALTOOLS_CLASS.SMAP_CalDiffSecsOfUTCGs(
        ScenarioStartTime,
        CZML_GENERALTOOLS_CLASS.ISO8601ToUtcgTimeTransformation(CurTime)
      )
      const diffSec2 = CZML_GENERALTOOLS_CLASS.SMAP_CalDiffSecsOfUTCGs(
        ScenarioEndTime,
        CZML_GENERALTOOLS_CLASS.ISO8601ToUtcgTimeTransformation(CurTime)
      )
      if (diffSec1 <= 0 && diffSec2 >= 0) {
        FindNode.data().clock.currentTime = CurTime
      }
    }
    // 删除之前的数据
    if (CZML_GENERALTOOLS_CLASS.CZML_LAYER) {
      viewer.removeLayer(CZML_GENERALTOOLS_CLASS.CZML_LAYER)
    }
    // 添加新数据
    const HEU_LoadCzml = new Array(CZML_GENERALTOOLS_CLASS.CzmlList.size())
    for (let i = 0; i < HEU_LoadCzml.length; i++) {
      HEU_LoadCzml[i] = CZML_GENERALTOOLS_CLASS.CzmlList.get(i).data()
    }
    // 上图
    CZML_GENERALTOOLS_CLASS.CZML_LAYER = new DE.CzmlLayer("CZML_GENERALTOOLS_CLASS", HEU_LoadCzml)
    viewer.addLayer(CZML_GENERALTOOLS_CLASS.CZML_LAYER)
    // const dataCzml = CZML_GENERALTOOLS_CLASS.DataSource.load(HEU_LoadCzml)
    // viewer.dataSources.add(dataCzml)
    // CZML_GENERALTOOLS_CLASS.DataSource.show = true
  }

  /**
   *将ISO8601格式的时间字符串转换为UTCG格式的时间字符串
   * @param strTime {string} 需转换的时间 ISO8601格式 “2017-11-29T23:16:39.8020000000033Z”
   * @returns {string}UTCG格式的时间
   * @constructor
   */
  static ISO8601ToUtcgTimeTransformation(strTime) {
    strTime += ""

    strTime = strTime.substr(0, strTime.length - 1)
    const strSplitTime = strTime.split("T")
    const strYMD = strSplitTime[0].split("-")
    const outTime = strYMD[2] + " " + CZML_GENERALTOOLS_CLASS.HEU_StrMonthRev[strYMD[1]] + " " + strYMD[0] + " " + strSplitTime[1]
    return outTime
  }

  /**
   * 将UTCG格式的时间字符串转换为ISO8601格式的字符串
   * @param strTime {string} 需转换的时间 UTCG格式 “29 Nov 2017 23:16:39.8020000000033”
   * @returns {string}ISO8601格式的时间
   * @constructor
   */
  static Utcg2ISO8601TimeTransformation(strTime) {
    strTime += ""
    const strSplitTime = strTime.split(" ")
    return (
      strSplitTime[2] +
      "-" +
      CZML_GENERALTOOLS_CLASS.HEU_StrMonth[strSplitTime[1]] +
      "-" +
      CZML_GENERALTOOLS_CLASS.HEU_StrDay[parseInt(strSplitTime[0]) - 1] +
      "T" +
      strSplitTime[3] +
      "Z"
    )
  }

  // 大地经纬度转笛卡尔坐标
  // geodetic：大地经纬度数组,单位为度和米[经度，纬度，高度]
  // 返回笛卡尔坐标数组[x,y,z]，单位为米
  static GeodeticToCartesianCoordinateTransformation(geodetic) {
    const geodetic_rad = new Cesium.Cartographic(Cesium.Math.toRadians(geodetic[0]), Cesium.Math.toRadians(geodetic[1]), geodetic[2])
    const cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(geodetic_rad)
    return [cartesianPosition.x, cartesianPosition.y, cartesianPosition.z]
  }

  // 笛卡尔坐标转大地经纬度
  // cartesian：笛卡尔坐标数组[x,y,z]，单位为米
  // 返回大地经纬度数组,单位为度和米[经度，纬度，高度]
  static CartesianToGeodeticCoordinateTransformation(cartesian) {
    const cartesianPosition = new Cesium.Cartesian3(cartesian[0], cartesian[1], cartesian[2])
    const geodeticPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesianPosition)
    return [Cesium.Math.toDegrees(geodeticPosition.longitude), Cesium.Math.toDegrees(geodeticPosition.latitude), geodeticPosition.height]
  }

  // 根据id获取模型库中模型对象位置信息
  // id：该对象ID，UUID字符串（包括火箭、车辆等）
  // relSecs：相对秒数（数据起始时刻），数值
  // return：位置数组:[x,y,z]
  static FindModelObjectInformation(id, relSecs) {
    // 找到该对象
    const FindObjectNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })
    if (FindObjectNode === null) {
      return [null, null, null]
    }
    if (FindObjectNode.data().position !== undefined) {
      let posData
      if (FindObjectNode.data().position.cartesian !== undefined) {
        // cartesian格式的数据
        posData = FindObjectNode.data().position.cartesian
      } else {
        posData = FindObjectNode.data().position.cartographicDegrees // cartographicDegrees格式的数据
      }
      // 二分法查找
      const dataLength = posData.length / 4
      // 判断relSecs是否在数据时间范围内
      if (posData[0] <= relSecs && posData[posData.length - 4] >= relSecs) {
        let nStart = 0
        let nEnd = dataLength - 1
        let nMid = Math.round((nStart + nEnd) / 2)
        while (nStart < nEnd - 1) {
          if (posData[nMid * 4] >= relSecs) {
            nEnd = nMid
          } else {
            nStart = nMid
          }
          nMid = Math.round((nStart + nEnd) / 2)
        }
        if (posData[nMid * 4 + 4] === undefined) {
          const real1 = [posData[nMid * 4 + 1], posData[nMid * 4 + 2], posData[nMid * 4 + 3]]
          return real1
        } else {
          const real = Cesium.LagrangePolynomialApproximation.interpolateOrderZero(
            relSecs,
            [posData[nMid * 4 - 4], posData[nMid * 4]],
            [
              posData[nMid * 4 - 3],
              posData[nMid * 4 - 2],
              posData[nMid * 4 - 1],
              posData[nMid * 4 + 1],
              posData[nMid * 4 + 2],
              posData[nMid * 4 + 3]
            ],
            3
          )
          return real
        }
      }
    }
    return [null, null, null]
  }

  // 将UTCG格式的时间字符串转换为修改儒略日（浮点数，单位为天）
  // strTime：UTCG格式字符串，29 Nov 2017 23:16:39.8020000000033
  static SMAP_ConvertUTCGToMjd(strTime) {
    strTime += ""
    const strSplitTime = strTime.split(" ")
    // let nYear, nMonth, nDay, nHour, nMin, dSec
    // 先获取年月日
    const nYear = parseInt(strSplitTime[2])
    const nMonth = parseInt(CZML_GENERALTOOLS_CLASS.HEU_StrMonth[strSplitTime[1]])
    const nDay = parseInt(strSplitTime[0])
    // 获取时分秒
    const strHMS = strSplitTime[3].split(":")
    const nHour = parseInt(strHMS[0])
    const nMin = parseInt(strHMS[1])
    const dSec = parseFloat(strHMS[2])
    // 计算儒略日
    const computeYearMon = parseInt((7 * (nYear + parseInt((nMonth + 9) / 12))) / 4)
    const computeMonth = parseInt((275 * nMonth) / 9)
    const fractionalDay = ((dSec / 60.0 + nMin) / 60 + nHour) / 24.0

    // 返回儒略日
    return 367 * nYear - computeYearMon + computeMonth + nDay + 1721013.5 + fractionalDay - CZML_GENERALTOOLS_CLASS.SMAP_JD_MJD_OFFSET
  }

  // 将修改儒略日转UTCG格式的时间字符串（29 Nov 2017 23:16:39.8020000000033）
  // mjd：修改儒略日（浮点数，单位为天）
  static SMAP_ConvertMjdToUTCG(mjd) {
    // 计算儒略日
    const jd = mjd + CZML_GENERALTOOLS_CLASS.SMAP_JD_MJD_OFFSET

    let seconds = (jd + 0.5 - parseInt(jd + 0.5)) * CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_DAY
    seconds = Math.round(seconds * 1e3) / 1e3
    let J = parseInt(jd + 0.5)
    if (seconds >= CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_DAY) {
      seconds -= CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_DAY
      J += 1
    }
    // 参数计算
    const N = parseInt((4 * (J + 68569)) / 146097)
    const L1 = J + 68569 - parseInt((N * 146097 + 3) / 4)
    const Y1 = parseInt((4000 * (L1 + 1)) / 1461001)
    const L2 = L1 - parseInt((1461 * Y1) / 4) + 31
    const M1 = parseInt((80 * L2) / 2447)
    const L3 = parseInt(M1 / 11)
    const D1 = parseInt(L2 - parseInt((2447 * M1) / 80))

    // 计算年月日时分秒
    const Y = 100 * (N - 49) + Y1 + L3
    const M = M1 + 2 - 12 * L3
    const D = D1
    const h = Math.floor(seconds / CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_HOUR)
    seconds -= h * CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_HOUR
    const m = Math.floor(seconds / CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_MINUTE)
    seconds -= m * CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_MINUTE
    const s = Math.round(seconds * 1e3) / 1e3

    // 转化为UTCG的字符串
    const strDateTime = String(D) + " " + String(M - 1) + " " + String(Y) + " " + String(h) + ":" + String(m) + ":" + String(s)

    return strDateTime
  }

  // 计算两个时间的时间差（都是UTCG格式）(utcg1 - utcg2)
  static SMAP_CalDiffSecsOfUTCGs(utcg1, utcg2) {
    return (
      (CZML_GENERALTOOLS_CLASS.SMAP_ConvertUTCGToMjd(utcg1) - CZML_GENERALTOOLS_CLASS.SMAP_ConvertUTCGToMjd(utcg2)) *
      CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_DAY
    )
  }

  // 在UTCG基准时间的基础上增加相对秒数（可为正负的浮点数）
  static SMAP_AddSecsOnBaseUtcg(baseUTCG, addSecs) {
    return CZML_GENERALTOOLS_CLASS.SMAP_ConvertMjdToUTCG(
      CZML_GENERALTOOLS_CLASS.SMAP_ConvertUTCGToMjd(baseUTCG) + addSecs / CZML_GENERALTOOLS_CLASS.SMAP_SECS_PER_DAY
    )
  }

  static NewScenario(strStartTime, strEndTime, strScenarioName, viewer) {
    // UTCG时间转换，保存场景时间
    // const StartTime = CZML_GENERALTOOLS_CLASS.Utcg2ISO8601TimeTransformation(strStartTime)
    // const EndTime = CZML_GENERALTOOLS_CLASS.Utcg2ISO8601TimeTransformation(strEndTime)
    CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime = strStartTime + "/" + strEndTime
    const ScenarioData = {
      id: "document",
      name: strScenarioName,
      version: "1.0",
      clock: {
        interval: CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime,
        currentTime: strStartTime,
        multiplier: 0,
        range: "LOOP_STOP",
        step: "SYSTEM_CLOCK_MULTIPLIER"
      }
    }
    const ret = CZML_GENERALTOOLS_CLASS.InsertModelObjectInformation("document", ScenarioData, true)
    CZML_GENERALTOOLS_CLASS.Upper(viewer)
    return ret
  }

  static AddOrbitObject(
    id,
    name,
    OrbitStartTime,
    OrbitEndTime,
    position,
    orientation,
    ModelVisible,
    Model3DPath,
    ModelSize,
    MarkerVisible,
    MarkerPath,
    MaekerPixelSize,
    MarkerColor,
    MarkerXOriginPos,
    MarkerYOriginPos,
    OrbitLineStyle,
    OrbitLineWidth,
    OrbitColor,
    OrbitVisible,
    Distance
  ) {
    const sOrbitStartTime = CZML_GENERALTOOLS_CLASS.Utcg2ISO8601TimeTransformation(OrbitStartTime)
    const sOrbitEndTime = CZML_GENERALTOOLS_CLASS.Utcg2ISO8601TimeTransformation(OrbitEndTime)
    const AvailabilityTime = sOrbitStartTime + "/" + sOrbitEndTime
    const OrbitObject = {
      id: id,
      availability: AvailabilityTime,
      name: name,
      billboard: {
        eyeOffset: {
          cartesian: [0, 0, 0]
        },
        horizontalOrigin: MarkerXOriginPos,
        distanceDisplayCondition: {
          distanceDisplayCondition: [Distance]
        },
        image: MarkerPath,
        pixelOffset: {
          cartesian2: [0, 0]
        },
        scale: MaekerPixelSize,
        show: MarkerVisible,
        verticalOrigin: MarkerYOriginPos
      },
      label: {
        fillColor: {
          rgba: MarkerColor
        },
        font: "11pt Lucida Console",
        horizontalOrigin: "LEFT",
        pixelOffset: {
          cartesian2: [10, 0]
        },
        show: MarkerVisible,
        style: "FILL_AND_OUTLINE",
        text: name,
        verticalOrigin: "CENTER"
      },
      path: {
        show: [
          {
            interval: CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime,
            boolean: OrbitVisible
          }
        ],
        width: OrbitLineWidth,
        material: CZML_GENERALTOOLS_CLASS.GetMaterialObject(OrbitLineStyle, OrbitColor),
        resolution: 120
      },
      model: {
        gltf: Model3DPath,
        scale: ModelSize,
        distanceDisplayCondition: {
          distanceDisplayCondition: [0, Distance]
        },
        show: ModelVisible,
        runAnimations: false
      },
      position: {
        interpolationAlgorithm: "LAGRANGE",
        interpolationDegree: 2,
        referenceFrame: "FIXED",
        epoch: sOrbitStartTime,
        cartesian: position
      },
      orientation: {
        interpolationAlgorithm: "LAGRANGE",
        interpolationDegree: 1,
        epoch: sOrbitStartTime,
        unitQuaternion: orientation
      }
    }
    return CZML_GENERALTOOLS_CLASS.InsertModelObjectInformation(id, OrbitObject, true)
  }

  // 向量相减
  static VectorMinus(Vector1, Vector2) {
    const Vector = [0, 0, 0]
    Vector[0] = Vector1[0] - Vector2[0]
    Vector[1] = Vector1[1] - Vector2[1]
    Vector[2] = Vector1[2] - Vector2[2]
    return Cesium.Cartesian3.fromElements(Vector[0], Vector[1], Vector[2])
  }

  // 计算场景内两个向量的夹角
  // origin_id1：向量1原点的id，uuid
  // end_id1：向量1终点的id，uuid
  // origin_id2：向量2原点的id，uuid
  // end_id2：向量2终点的id，uuid
  static HEU_CalcTwoVectorsAngle(viewer, origin_id1, end_id1, origin_id2, end_id2) {
    if (
      !(
        Cesium.defined(viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id1)) &&
        Cesium.defined(viewer.dataSources._dataSources[0]._entityCollection.getById(end_id1)) &&
        Cesium.defined(viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id2)) &&
        Cesium.defined(viewer.dataSources._dataSources[0]._entityCollection.getById(end_id2))
      )
    ) {
      return -1
    }
    // 当前时刻原点位置
    const OriginPos1 = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id1).position._property._interpolationResult
    const OriginPos2 = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id2).position._property._interpolationResult
    // 当前时刻终点位置
    const EndPos1 = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id1).position._property._interpolationResult
    const EndPos2 = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id2).position._property._interpolationResult
    if (OriginPos1[0] === undefined || OriginPos2[0] === undefined || EndPos1[0] === undefined || EndPos2[0] === undefined) {
      OriginPos1[0] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id1).position._property._values[0]
      OriginPos1[1] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id1).position._property._values[1]
      OriginPos1[2] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id1).position._property._values[2]
      OriginPos2[0] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id2).position._property._values[0]
      OriginPos2[1] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id2).position._property._values[1]
      OriginPos2[2] = viewer.dataSources._dataSources[0]._entityCollection.getById(origin_id2).position._property._values[2]
      // 当前时刻终点位置
      EndPos1[0] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id1).position._property._values[0]
      EndPos1[1] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id1).position._property._values[1]
      EndPos1[2] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id1).position._property._values[2]
      EndPos2[0] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id2).position._property._values[0]
      EndPos2[1] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id2).position._property._values[1]
      EndPos2[2] = viewer.dataSources._dataSources[0]._entityCollection.getById(end_id2).position._property._values[2]
    }
    // 计算两个向量之间的夹角
    const vector1 = CZML_GENERALTOOLS_CLASS.VectorMinus(EndPos1, OriginPos1)
    const vector2 = CZML_GENERALTOOLS_CLASS.VectorMinus(EndPos2, OriginPos2)
    const Angle = Cesium.Cartesian3.angleBetween(vector1, vector2)

    return Angle
  }

  // 增加角度展示
  // ReferenceFrame:轨迹姿态的参考系设定，字符串，两种可选（"FIXED" ，"INERTIAL"）默认为"FIXED"
  static HEU_AddAngleDisplayObject(id, origin_id1, lineStartId, origin_id2, lineEndId, DataStartTime, PosMid, AgnleColor, viewer, ReferenceFrame) {
    const AngleLineId = id + "-Angle-Line"
    const AngleLine = {
      id: AngleLineId,
      name: AngleLineId,
      availability: CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime,
      polyline: {
        show: [
          {
            interval: CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime,
            boolean: true
          }
        ],
        width: 1,
        material: {
          solidColor: {
            color: {
              rgba: AgnleColor
            }
          }
        },
        followSurface: false,
        positions: {
          references: [lineStartId + "#position", lineEndId + "#position"]
        }
      }
    }

    // 角度label
    const AngleLableId = id + "-Angle-Label"
    const sDataStartTime = CZML_GENERALTOOLS_CLASS.Utcg2ISO8601TimeTransformation(DataStartTime)
    const AngleLable = {
      id: AngleLableId,
      name: AngleLableId,
      availability: CZML_GENERALTOOLS_CLASS.HEU_ScenarioTime,
      show: true,
      label: {
        fillColor: {
          rgba: [255, 255, 0, 255]
        },
        font: "11pt Lucida Console",
        horizontalOrigin: "CENTER",
        pixelOffset: {
          cartesian2: [30, 10]
        },
        show: true,
        style: "FILL_AND_OUTLINE",
        text: "",
        verticalOrigin: "CENTER"
      },
      position: {
        interpolationAlgorithm: "LAGRANGE",
        interpolationDegree: 5,
        referenceFrame: "ReferenceFrame",
        epoch: sDataStartTime,
        cartesian: PosMid
      }
    }
    const rst1 = CZML_GENERALTOOLS_CLASS.InsertModelObjectInformation(AngleLineId, AngleLine, true)
    const rst2 = CZML_GENERALTOOLS_CLASS.InsertModelObjectInformation(AngleLableId, AngleLable, true)
    CZML_GENERALTOOLS_CLASS.Upper(this._viewer)

    // 添加事件
    if (CZML_GENERALTOOLS_CLASS.AngleDisplayEvent.has(id)) {
      return false
    }
    const Ids = [origin_id1, lineStartId, origin_id2, lineEndId, AngleLableId]
    CZML_GENERALTOOLS_CLASS.AngleDisplayEvent.set(id + "angle_event", Ids)
    const EventFunction = function AngleDisplayEventFunction() {
      CZML_GENERALTOOLS_CLASS.AngleDisplayEvent.forEach(function (value, key) {
        const angel = ((CZML_GENERALTOOLS_CLASS.HEU_CalcTwoVectorsAngle(value[0], value[1], value[2], value[3]) * 180) / Math.PI).toFixed(2)
        viewer.dataSources._dataSources[0]._entityCollection.getById(value[4])._label.text = angel.toString() + " deg"
      })
    }
    if (CZML_GENERALTOOLS_CLASS.AngleDisplayEvent.size === 1) {
      const HEU_AngleDisplayEventFunc = EventFunction
      viewer.scene.preRender.addEventListener(HEU_AngleDisplayEventFunc)
    }

    return rst1 && rst2
  }

  // 坐标轴两个轴之间的角度添加
  // 该角度的id，UUID
  // origin_id1：坐标轴1原点的id，uuid，比如火箭的id
  // AxisId1：坐标轴1的id，uuid
  // AxisName1：坐标轴1对应的轴名称，必须为{“x”, "y", "z"}三者之一，注意小写
  // origin_id2：坐标轴2原点的id，uuid，比如火箭的id
  // AxisId2：坐标轴2的id，uuid
  // AxisName2：坐标轴2对应的轴名称，必须为{“x”, "y", "z"}三者之一，注意小写
  // DataStartTime：数据开始时刻，字符串，输入格式为UTCG
  // PosMid：两个轴之间的中点位置数，数组：[相对秒1,X1,Y1,Z1,相对秒2,X2,Y2,Z2]([0,30,30,30,5,30,30,30])，XYZ为地心地固系下，单位为米
  // AgnleColor：角度的颜色，数组：[R,G,B,255]（[255,0,0,255]）
  // ReferenceFrame:轨迹姿态的参考系设定，字符串，两种可选（"FIXED" ，"INERTIAL"）默认为"FIXED"
  static AxisAngleAdd(id, origin_id1, AxisId1, AxisName1, origin_id2, AxisId2, AxisName2, DataStartTime, PosMid, AgnleColor) {
    const end_id1 = AxisId1 + "-to-axis-point" + AxisName1
    const end_id2 = AxisId2 + "-to-axis-point" + AxisName2
    // 计算角度值
    const Angle = CZML_GENERALTOOLS_CLASS.HEU_CalcTwoVectorsAngle(origin_id1, end_id1, origin_id2, end_id2)
    if (Angle < 0) {
      return Angle
    }
    return CZML_GENERALTOOLS_CLASS.HEU_AddAngleDisplayObject(id, origin_id1, end_id1, origin_id2, end_id2, DataStartTime, PosMid, AgnleColor)
  }

  // 向量和坐标轴某个轴之间的角度添加
  // 该角度的id，UUID
  // origin_id1：坐标轴1原点的id，uuid，比如火箭的id
  // AxisId1：坐标轴1的id，uuid
  // AxisName1：坐标轴1对应的轴名称，必须为{“x”, "y", "z"}三者之一，注意小写
  // origin_id2：向量原点的id，uuid，比如火箭的id
  // DynamicLineId：向量的id，uuid
  // DataStartTime：数据开始时刻，字符串，输入格式为UTCG
  // PosMid：两个轴之间的中点位置数，数组：[相对秒1,X1,Y1,Z1,相对秒2,X2,Y2,Z2]([0,30,30,30,5,30,30,30])，XYZ为地心地固系下，单位为米
  // AgnleColor：角度的颜色，数组：[R,G,B,255]（[255,0,0,255]）
  // ReferenceFrame:轨迹姿态的参考系设定，字符串，两种可选（"FIXED" ，"INERTIAL"）默认为"FIXED"
  static HEU_AxisLineAngleAdd(id, origin_id1, AxisId1, AxisName1, origin_id2, DynamicLineId, DataStartTime, PosMid, AgnleColor, ReferenceFrame) {
    const end_id1 = AxisId1 + "-to-axis-point" + AxisName1
    const end_id2 = DynamicLineId + "-to-dline-pos2"
    // 计算角度值
    const Angle = CZML_GENERALTOOLS_CLASS.HEU_CalcTwoVectorsAngle(origin_id1, end_id1, origin_id2, end_id2)
    if (Angle < 0) {
      return Angle
    }

    return CZML_GENERALTOOLS_CLASS.HEU_AddAngleDisplayObject(
      id,
      origin_id1,
      end_id1,
      origin_id2,
      end_id2,
      DataStartTime,
      PosMid,
      AgnleColor,
      ReferenceFrame
    )
  }

  // 两个向量之间的角度添加
  // 该角度的id，UUID
  // origin_id1：向量1原点的id，uuid，比如火箭的id
  // DynamicLineId1：向量的id，uuid
  // origin_id2：向量2原点的id，uuid，比如火箭的id
  // DynamicLineId2：向量的id，uuid
  // DataStartTime：数据开始时刻，字符串，输入格式为UTCG
  // PosMid：两个轴之间的中点位置数，数组：[相对秒1,X1,Y1,Z1,相对秒2,X2,Y2,Z2]([0,30,30,30,5,30,30,30])，XYZ为地心地固系下，单位为米
  // AgnleColor：角度的颜色，数组：[R,G,B,255]（[255,0,0,255]）
  // ReferenceFrame:轨迹姿态的参考系设定，字符串，两种可选（"FIXED" ，"INERTIAL"）默认为"FIXED"
  static HEU_TwoLineAngleAdd(id, origin_id1, DynamicLineId1, origin_id2, DynamicLineId2, DataStartTime, PosMid, AgnleColor) {
    const end_id1 = DynamicLineId1 + "-to-dline-pos2"
    const end_id2 = DynamicLineId2 + "-to-dline-pos2"
    // 计算角度值
    const Angle = CZML_GENERALTOOLS_CLASS.HEU_CalcTwoVectorsAngle(origin_id1, end_id1, origin_id2, end_id2)
    if (Angle < 0) {
      return Angle
    }

    return CZML_GENERALTOOLS_CLASS.HEU_AddAngleDisplayObject(id, origin_id1, end_id1, origin_id2, end_id2, DataStartTime, PosMid, AgnleColor)
  }

  // 控制场景内对象是否显示
  // id：该对象ID，UUID字符串
  // visible：该对象是否显示，false为不显示，true为显示
  // type：对象类型，1为地面站或轨迹物体关键点、2空天轨道对象（航天器等），3为地面有轨迹对象（运动车等），4为多边形，5为椭圆，6为矩形，7为动态线或坐标轴，8为显示夹角
  static SetObjectVisible(id, visible, type, viewer) {
    // 查询该id相关的所有元素
    const MapNodes = CZML_GENERALTOOLS_CLASS.CzmlList.map(function (node) {
      return node.data().id.includes(id)
    })

    // 循环遍历修改所有对象的visible属性
    for (let i = 0; i < MapNodes.length; i++) {
      // 外部id对象
      if (MapNodes[i].data().id === id) {
        if (type === 1) {
          // 地面站
          if (MapNodes[i].data().model !== undefined) {
            MapNodes[i].data().model.show = visible
          }
          MapNodes[i].data().billboard.show = visible
          MapNodes[i].data().label.show = visible
        } else if (type === 2) {
          // 空天轨道对象
          MapNodes[i].data().model.show = visible
          MapNodes[i].data().billboard.show = visible
          MapNodes[i].data().label.show = visible
        } else if (type === 3) {
          // 地面轨迹对象
          MapNodes[i].data().model.show = visible
          MapNodes[i].data().billboard.show = visible
          MapNodes[i].data().label.show = visible
          MapNodes[i].data().path.show[0].boolean = visible

          const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
            return node.data().id === id
          })
          // 如果存在直接替换
          // if (FindNode !== null) {
          //   FindNode.data(data)
          //   return false
          // } else {
          //   CZML_GENERALTOOLS_CLASS.CzmlList.push(data)
          //   return true
          // }
        } else if (type === 4) {
          // 多边形
          MapNodes[i].data().polygon.show = visible
        } else if (type === 5) {
          // 椭圆
          MapNodes[i].data().ellipse.show = visible
        } else if (type === 6) {
          // 矩形
          MapNodes[i].data().rectangle.show = visible
        }
      } else {
        // 内部id
        // 空白弧段+可见性弧段
        if (type === 2 && MapNodes[i].data().id.includes("-to-show")) {
          MapNodes[i].data().path.show[0].boolean = visible
        } else if (type !== 7 && MapNodes[i].data().id.includes("-to-") && !MapNodes[i].data().id.includes("show")) {
          // 通信弧段
          const strID = MapNodes[i].data().id
          // 判断通信两端对象是否显示
          // 获取通信两端对象的id
          const str1 = strID.substr(0, strID.indexOf("-to"))
          const str2 = strID.substr(strID.indexOf("to-") + 3, strID.lastIndexOf("-index") - strID.indexOf("to-") - 3)
          let IsVisible = true
          if (str1 === id) {
            // 判断str2的显示状态
            const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
              return node.data().id === str2
            })
            if (FindNode !== null) {
              IsVisible = FindNode.data().model.show
            }
          } else {
            // 判断str1的显示状态
            const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
              return node.data().id === str1
            })
            if (FindNode !== null) {
              IsVisible = FindNode.data().model.show
            }
          }
          if (IsVisible === true) {
            MapNodes[i].data().polyline.show[0].boolean = visible
          }
        } else if (type === 7 || type === 8) {
          // 动态线或动态坐标轴
          if (MapNodes[i].data().show !== undefined) {
            MapNodes[i].data().show = visible
          }
          if (MapNodes[i].data().label !== undefined) {
            MapNodes[i].data().label.show = visible
          }
          if (MapNodes[i].data().polyline !== undefined) {
            MapNodes[i].data().polyline.show[0].boolean = visible
          }
        }
      }
    }
    if (MapNodes.length > 0) {
      // 上图
      CZML_GENERALTOOLS_CLASS.Upper(viewer)
      return true
    } else {
      return false
    }
  }

  // 是否显示晨昏线
  // enable：true：显示晨昏线，false：不显示晨昏线
  static HEU_EnableLighting(enable, viewer) {
    viewer.scene.globe.enableLighting = enable
  }

  // 返回cesium支持的线型对象（内部使用）
  // OrbitLineStyle：<Number> 轨迹风格，0代表直线，1代表虚线
  // OrbitColor：<Array> 轨迹颜色，[R,G,B,255]（[255,0,0,255]）
  // return：<Object> 模型的材料属性
  static GetMaterialObject(OrbitLineStyle, OrbitColor) {
    let material
    if (OrbitLineStyle === 1) {
      // 虚线
      material = {
        polylineDash: {
          color: {
            rgba: OrbitColor
          }
        }
      }
    } else {
      // 直线
      material = {
        solidColor: {
          color: {
            rgba: OrbitColor
          }
        }
      }
    }
    return material
  }

  // 获取轨迹物体某个相对秒数的姿态（返回弧度值）
  // id：该对象ID，UUID字符串（包括火箭、车辆等）
  // relSecs：相对秒数（数据起始时刻）
  // return: <Array> 输入姿态为四元数，返回为欧拉角
  static FindModelAttitudeInformation(id, relSecs) {
    let real
    // 找到该对象
    const FindObjectNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })
    if (FindObjectNode === null) {
      return [null, null, null, null]
    }
    if (FindObjectNode.data().orientation !== undefined) {
      let posData
      if (FindObjectNode.data().orientation.unitQuaternion !== undefined) {
        // Quaternion
        posData = FindObjectNode.data().orientation.unitQuaternion
      } else {
        posData = FindObjectNode.data().orientation.unitQuaternion // cartographicDegrees
      }
      // 二分法查找
      const dataLength = posData.length / 5
      if (posData[0] <= relSecs && posData[posData.length - 5] >= relSecs) {
        let nStart = 0
        let nEnd = dataLength - 1
        let nMid = Math.round((nStart + nEnd) / 2)
        while (nStart < nEnd - 1) {
          if (posData[nMid * 5] >= relSecs) {
            nEnd = nMid
          } else {
            nStart = nMid
          }
          nMid = Math.round((nStart + nEnd) / 2)
        }
        if (posData[nMid * 5 + 5] === undefined) {
          real = [posData[nMid * 5 + 1], posData[nMid * 5 + 2], posData[nMid * 5 + 3], posData[nMid * 5 + 4]]
          // return real;
        } else {
          real = Cesium.LagrangePolynomialApproximation.interpolateOrderZero(
            relSecs,
            [posData[nMid * 5 - 5], posData[nMid * 5]],
            [
              posData[nMid * 5 - 4],
              posData[nMid * 5 - 3],
              posData[nMid * 5 - 2],
              posData[nMid * 5 - 1],
              posData[nMid * 5 + 1],
              posData[nMid * 5 + 2],
              posData[nMid * 5 + 3],
              posData[nMid * 5 + 4]
            ],
            4
          )
          // return real;
        }
      }
      // 转换为弧度
      const x = real[0]
      const y = real[1]
      const z = real[2]
      const w = real[3]
      const Quaternion = new Cesium.Quaternion(x, y, z, w)
      const hpr = Cesium.HeadingPitchRoll.fromQuaternion(Quaternion)
      return hpr
    }
  }

  // 添加返回某对象实时位置/姿态数据事件
  // id：要获取数据的轨道对象id，uuid，比如火箭的id
  static AddOrbitObjectPosAttiEvent(id, showCoord, viewer) {
    if (!Cesium.defined(viewer.dataSources._dataSources[0]._entityCollection.getById(id))) {
      return -1
    }
    // 保存该id
    if (CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.has(id)) {
      return -2
    }
    CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.add(id)
    // 事件函数
    const EventFunction = function GetObjectPosAttiData() {
      const utc = CZML_GENERALTOOLS_CLASS.ISO8601ToUtcgTimeTransformation(Cesium.JulianDate.toIso8601(viewer.clock.currentTime))
      const RelSec = []
      const ids = []
      const names = []
      const pos = []
      const atti = []
      CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.forEach(function (element) {
        ids.push(element)
        names.push(viewer.dataSources._dataSources[0]._entityCollection.getById(element)._label.text._value)
        RelSec.push(
          Cesium.JulianDate.secondsDifference(
            viewer.clock.currentTime,
            viewer.dataSources._dataSources[0]._entityCollection.getById(element).position._property._times[0]
          )
        )
        const length = viewer.dataSources._dataSources[0]._entityCollection.getById(element).position._property._times.length
        if (
          Cesium.JulianDate.lessThan(
            viewer.clock.currentTime,
            viewer.dataSources._dataSources[0]._entityCollection.getById(element).position._property._times[0]
          ) ||
          Cesium.JulianDate.greaterThan(
            viewer.clock.currentTime,
            viewer.dataSources._dataSources[0]._entityCollection.getById(element).position._property._times[length - 1]
          )
        ) {
          pos.push(undefined)
          atti.push(undefined)
        } else {
          pos.push(viewer.dataSources._dataSources[0]._entityCollection.getById(element).position._property._interpoationResult)
          atti.push(viewer.dataSources._dataSources[0]._entityCollection.getById(element).orientation._interpolationResult)
        }
      })
      showCoord(utc, RelSec, ids, names, pos, atti)
    }
    if (CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.size === 1) {
      CZML_GENERALTOOLS_CLASS.GetPosAttiEventFunc = EventFunction
      viewer.clock.onTick.addEventListener(CZML_GENERALTOOLS_CLASS.GetPosAttiEventFunc)
    }
    return 0
  }

  // 删除返回某对象实时位置/姿态数据事件
  // id：要获取数据的轨道对象id，uuid，比如火箭的id
  static DeleteOrbitObjectPosAttiEvent(id, viewer) {
    CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.delete(id)
    // 判断是否用事件监听函数需要删除
    if (CZML_GENERALTOOLS_CLASS.GetPosAttiEventId.size === 0) {
      // 取消监听
      viewer.clock.onTick.removeEventListener(CZML_GENERALTOOLS_CLASS.GetPosAttiEventFunc)
    }
  }

  // 连续取点触发接口
  static ContinuityClick(viewer) {
    const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    handler.setInputAction(function (id) {
      const cartesian = viewer.camera.pickEllipsoid(id.position, viewer.scene.globe.ellipsoid)
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
      const Pointlongitude = Cesium.Math.toDegrees(cartographic.longitude) // 经度值
      const Pointlatitude = Cesium.Math.toDegrees(cartographic.latitude) // 纬度值
      viewer.entities.add({
        position: cartesian,
        point: {
          pixelSize: 6, // 地图上显示的点大小
          color: Cesium.Color.YELLOW // 地图上显示的点颜色
        }
      })
      const PointPos = [Pointlongitude, Pointlatitude]
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    handler.setInputAction(function Stopclick() {
      viewer.entities.removeAll()
      handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) // 右键点击任意位置退出取点环境
  }

  // 单次取点触发接口
  static SingleLeftMouseClick(viewer) {
    const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    handler.setInputAction(function (id) {
      const cartesian = viewer.camera.pickEllipsoid(id.position, viewer.scene.globe.ellipsoid)
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
      const Pointlongitude = Cesium.Math.toDegrees(cartographic.longitude) // 经度值
      const Pointlatitude = Cesium.Math.toDegrees(cartographic.latitude) // 纬度值
      const PointPos = [Pointlongitude, Pointlatitude]
      window.parent.portal.getPointPos(PointPos)
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    handler.setInputAction(function Stopclick() {
      handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) // 右键点击任意位置退出取点环境
  }

  // 拉格朗日插值（输入样本点生成多组数）
  static LagrangePolynomialApproximation(
    samplePositions,
    startTime,
    stopTimeSeconds,
    degree /// 输入数组，
  ) {
    let interpolationDegree = degree
    if (!interpolationDegree) {
      interpolationDegree = 2
    }
    // 29 Nov 201
    // let t1 = Cesium.JulianDate.fromDate(new Date(2017, 11, 29, 22,));2293.06 "29 Nov 2017 22:44:11.000"
    const t1 = Cesium.JulianDate.fromIso8601(startTime) // shuru
    // let t2 = Cesium.JulianDate.addSeconds(t1, 2293.06, new Cesium.JulianDate());//quanbuxiangduimaoshu
    const timeStep = stopTimeSeconds / (samplePositions.length - 1)
    const positionProperty = new Cesium.SampledPositionProperty()
    positionProperty.addSample(t1, samplePositions[0])
    for (let i = 1; i < samplePositions.length; i++) {
      positionProperty.addSample(Cesium.JulianDate.addSeconds(t1, i * timeStep, new Cesium.JulianDate()), samplePositions[i])
    }
    positionProperty.setInterpolationOptions({
      interpolationDegree: 2,
      interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
    })

    const outTimeStep = stopTimeSeconds / (3000 - 1)
    const outPositions = []
    const res = {}
    for (let i = 0; i < 3000; i++) {
      const outPosition = positionProperty.getValue(
        Cesium.JulianDate.addSeconds(t1, i * outTimeStep, new Cesium.JulianDate()),
        new Cesium.Cartesian3()
      )
      outPositions.push(outPosition)
    }

    const timeStep1 = stopTimeSeconds / (outPositions.length - 1)
    const positionProperty1 = new Cesium.SampledPositionProperty()
    positionProperty1.addSample(t1, outPositions[0])
    for (let i = 1; i < outPositions.length; i++) {
      positionProperty1.addSample(Cesium.JulianDate.addSeconds(t1, i * timeStep1, new Cesium.JulianDate()), outPositions[i])
    }
    positionProperty1.setInterpolationOptions({
      interpolationDegree: interpolationDegree,
      interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
    })

    return { positions: positionProperty1, outPositions: outPositions }
  }

  // 根据指定的适配字符串删除所有的与其相关的场景对象
  // maskstr：<String> 适配字符串
  // return：<Boolean> 是否循环删除所有满足条件的节点
  static DeleteCesiumObjectsByMaskStr(maskstr) {
    const MapNodes = CZML_GENERALTOOLS_CLASS.CzmlList.map(function (node) {
      return node.data().id.includes(maskstr)
    })
    if (MapNodes.length <= 0) {
      return false
    }
    // 循环删除所有满足条件的节点
    for (let i = 0; i < MapNodes.length; i++) {
      CZML_GENERALTOOLS_CLASS.CzmlList.remove(MapNodes[i])
    }
    return true
  }

  static ModifyNonOrbitObject3DProperty(
    viewer,
    id,
    ModelVisible,
    ModelSize,
    MarkerVisible,
    MarkerPath,
    MaekerPixelSize,
    MarkerColor,
    MarkerXOriginPos,
    MarkerYOriginPos
  ) {
    // 查找对应id
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })

    // 修改三维属性
    if (FindNode !== null) {
      // 三维模型属性
      FindNode.data().model.show = ModelVisible
      FindNode.data().model.scale = ModelSize
      // 二维图标属性
      FindNode.data().billboard.show = MarkerVisible
      FindNode.data().label.show = MarkerVisible
      FindNode.data().billboard.image = MarkerPath
      FindNode.data().billboard.scale = MaekerPixelSize
      FindNode.data().label.fillColor.rgba = MarkerColor
      FindNode.data().billboard.horizontalOrigin = MarkerXOriginPos
      FindNode.data().billboard.verticalOrigin = MarkerYOriginPos
      // 上图
      CZML_GENERALTOOLS_CLASS.Upper(viewer)
    }
  }

  /**
   * 修改cesium场景中固定物体的位置
   * @param id <String> 该对象ID，UUID字符串
   * @param position <Array> 地面站位置，[经度,纬度,高度]([30,30,0])
   * @returns <Boolean> 位置是否改变
   */
  static ModifyNonOrbitObjectPosition(id, position, viewer) {
    // 查找对应id
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })

    // 修改固定物体位置
    if (FindNode !== null) {
      FindNode.data().position.cartographicDegrees = position

      // 上图
      CZML_GENERALTOOLS_CLASS.Upper(viewer)
      return true
    } else {
      return false
    }
  }

  static ModifyObjectName(id, name, viewer) {
    // 查找对应id
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })

    // 修改固定物体位置
    if (FindNode !== null) {
      FindNode.data().name = name
      FindNode.data().label.text = name

      // 上图
      CZML_GENERALTOOLS_CLASS.Upper(viewer)
      return true
    } else {
      return false
    }
  }

  /**
   * 判断地图上有没有某个物体
   * @param id <String> cesium场景中渲染对象ID，UUID字符串
   * @returns <boolean> 是否存在
   * @constructor
   */
  static CheckIDIsExit(id) {
    // 查找对应id
    const FindNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })
    if (FindNode !== null) {
      return true
    } else {
      return false
    }
  }

  // 修改cesium场景中含轨迹对象的三维属性
  // id：该对象ID，UUID字符串
  // ModelVisible：三维模型是否可见（true/false）
  // Model3DPath：三维模型路径，字符串
  // ModelSize：三维模型大小，数值（1000）
  // MarkerVisible：二维标签是否可见（true/false）
  // MarkerPath：二维标签图片路径，字符串
  // MaekerPixelSize：二维标签图片大小（1）
  // MarkerColor：二维标签颜色，数组：[R,G,B,255]（[255,0,0,255]）
  // MarkerXOriginPos：二维标签水平对齐，字符串，三种可选（"CENTER"，"LEFT"，"RIGHT"）
  // MarkerYOriginPos：二维标签垂直对齐，字符串，三种可选（"CENTER"，"LEFT"，"RIGHT"）
  // OrbitVisible：轨迹是否可见（true/false）
  // OrbitLineStyle：轨迹风格，0代表直线，1代表虚线
  // OrbitLineWidth：轨迹宽度，数值（4）
  // OrbitColor：轨迹颜色，数组：[R,G,B,255]（[255,0,0,255]）
  // return：true 属性是否改变
  static ModifyOrbitObject3DProperty(
    id,
    ModelVisible,
    Model3DPath,
    ModelSize,
    MarkerVisible,
    MarkerPath,
    MaekerPixelSize,
    MarkerColor,
    MarkerXOriginPos,
    MarkerYOriginPos,
    OrbitVisible,
    OrbitLineStyle,
    OrbitLineWidth,
    OrbitColor,
    viewer
  ) {
    // 查找对应id
    const FindObjectNode = CZML_GENERALTOOLS_CLASS.CzmlList.find(function (node) {
      return node.data().id === id
    })

    // 查找显示轨道id
    const MapShowNodes = CZML_GENERALTOOLS_CLASS.CzmlList.map(function (node) {
      return node.data().id.includes(id + "-to-show")
    })

    // 修改三维属性
    if (FindObjectNode === null) {
      return false
    }

    const material = CZML_GENERALTOOLS_CLASS.GetMaterialObject(OrbitLineStyle, OrbitColor)

    // 修改三维属性
    if (FindObjectNode !== null) {
      // 三维模型属性
      FindObjectNode.data().model.show = ModelVisible
      FindObjectNode.data().model.gltf = Model3DPath
      FindObjectNode.data().model.scale = ModelSize
      // 二维图标属性
      FindObjectNode.data().billboard.show = MarkerVisible
      FindObjectNode.data().label.show = MarkerVisible
      FindObjectNode.data().billboard.image = MarkerPath
      FindObjectNode.data().billboard.scale = MaekerPixelSize
      FindObjectNode.data().label.fillColor.rgba = MarkerColor
      FindObjectNode.data().billboard.horizontalOrigin = MarkerXOriginPos
      FindObjectNode.data().billboard.verticalOrigin = MarkerYOriginPos
      // 轨道属性
      if (MapShowNodes.length === 0) {
        FindObjectNode.data().path.show[0].boolean = OrbitVisible
      } else {
        FindObjectNode.data().path.show[0].boolean = false
      }
      FindObjectNode.data().path.width = OrbitLineWidth
      // 设置轨道的线性和颜色
      FindObjectNode.data().path.material = material
    }

    // 修改显示轨道的三维属性
    for (let i = 0; i < MapShowNodes.length; i++) {
      // 轨道属性
      MapShowNodes[i].data().path.show[0].boolean = OrbitVisible
      // 设置轨道的线性和颜色
      if (MapShowNodes[i].data().id.includes("blank")) {
        MapShowNodes[i].data().path.material = material
      } else {
        let SaveColor
        if (MapShowNodes[i].data().path.material.solidColor === undefined) {
          SaveColor = MapShowNodes[i].data().path.material.polylineDash.color
        } else {
          // 实线
          SaveColor = MapShowNodes[i].data().path.material.solidColor.color
        }
        if (OrbitLineStyle === 1) {
          // 虚线
          MapShowNodes[i].data().path.material = {
            polylineDash: {
              color: SaveColor
            }
          }
        } else {
          // 直线
          MapShowNodes[i].data().path.material = {
            solidColor: {
              color: SaveColor
            }
          }
        }
      }
    }
    // 上图
    CZML_GENERALTOOLS_CLASS.Upper(viewer)
    return true
  }

  static HEU_ControlAnimationNode(
    hiddenTimeSecs,
    zhengliuzhaoAStartTime,
    zhengliuzhaoBStartTime,
    xin01jiStartTime,
    xin02jiStartTime,
    zhutuiAStartTime,
    zhutuiBStartTime,
    zhutuiCStartTime,
    zhutuiDStartTime,
    shangmianjiStartTime,
    OverallSeconds,
    unBiasedPositionArray,
    BiasedPositionArray
  ) {
    const unBiasedTranslation = []
    const shangmianjiBiasedTranslation = []
    const xin02jiBiasedTranslation = []

    shangmianjiBiasedTranslation[4] = 1 // 设定移动到相机上的时间为1s
    shangmianjiBiasedTranslation[8] = Cesium.JulianDate.secondsDifference(
      Cesium.JulianDate.fromIso8601(shangmianjiStartTime),
      Cesium.JulianDate.fromIso8601(xin01jiStartTime)
    ) // 分离时间
    shangmianjiBiasedTranslation[5] = shangmianjiBiasedTranslation[9] = BiasedPositionArray[0]
    shangmianjiBiasedTranslation[6] = shangmianjiBiasedTranslation[10] = BiasedPositionArray[1]
    shangmianjiBiasedTranslation[7] = shangmianjiBiasedTranslation[11] = BiasedPositionArray[2]

    xin02jiBiasedTranslation[4] = 1 // 设定移动到相机上的时间为1s
    xin02jiBiasedTranslation[8] = Cesium.JulianDate.secondsDifference(
      Cesium.JulianDate.fromIso8601(xin02jiStartTime),
      Cesium.JulianDate.fromIso8601(xin01jiStartTime)
    ) // 分离时间
    xin02jiBiasedTranslation[5] = xin02jiBiasedTranslation[9] = BiasedPositionArray[0]
    xin02jiBiasedTranslation[6] = xin02jiBiasedTranslation[10] = BiasedPositionArray[1]
    xin02jiBiasedTranslation[7] = xin02jiBiasedTranslation[11] = BiasedPositionArray[2]

    for (let i = 0; i < unBiasedPositionArray.length; i++) {
      unBiasedTranslation[i] = unBiasedPositionArray[i]
      if (i <= 3) {
        xin02jiBiasedTranslation[i] = unBiasedPositionArray[i]
        shangmianjiBiasedTranslation[i] = unBiasedPositionArray[i]
      }
      if (i === unBiasedPositionArray.length - 1) {
        unBiasedTranslation[i + 1] = OverallSeconds
        unBiasedTranslation[i + 2] = unBiasedPositionArray[i - 2]
        unBiasedTranslation[i + 3] = unBiasedPositionArray[i - 1]
        unBiasedTranslation[i + 4] = unBiasedPositionArray[i]
        xin02jiBiasedTranslation[i + 1] = OverallSeconds
        xin02jiBiasedTranslation[i + 2] = unBiasedPositionArray[i - 2]
        xin02jiBiasedTranslation[i + 3] = unBiasedPositionArray[i - 1]
        xin02jiBiasedTranslation[i + 4] = unBiasedPositionArray[i]
        shangmianjiBiasedTranslation[i + 1] = OverallSeconds
        shangmianjiBiasedTranslation[i + 2] = unBiasedPositionArray[i - 2]
        shangmianjiBiasedTranslation[i + 3] = unBiasedPositionArray[i - 1]
        shangmianjiBiasedTranslation[i + 4] = unBiasedPositionArray[i]
      }
    }

    const Transformations = {
      zhengliuzhaoA: {
        scale: {
          epoch: zhengliuzhaoAStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhengliuzhaoAStartTime,
          cartesian: unBiasedTranslation
        }
      },
      zhengliuzhaoB: {
        scale: {
          epoch: zhengliuzhaoBStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhengliuzhaoBStartTime,
          cartesian: unBiasedTranslation
        }
      },
      xin01ji: {
        translation: {
          epoch: xin01jiStartTime,
          cartesian: unBiasedTranslation
        },
        scale: {
          epoch: xin01jiStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        }
      },
      xin02ji: {
        translation: {
          epoch: xin01jiStartTime,
          cartesian: xin02jiBiasedTranslation
        }
      },
      zhutuiA: {
        scale: {
          epoch: zhutuiAStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhutuiAStartTime,
          cartesian: unBiasedTranslation
        }
      },
      zhutuiB: {
        scale: {
          epoch: zhutuiBStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhutuiBStartTime,
          cartesian: unBiasedTranslation
        }
      },
      zhutuiC: {
        scale: {
          epoch: zhutuiCStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhutuiCStartTime,
          cartesian: unBiasedTranslation
        }
      },
      zhutuiD: {
        scale: {
          epoch: zhutuiDStartTime,
          cartesian: [0.0, 1.0, 1.0, 1.0, hiddenTimeSecs, 0, 0, 0, OverallSeconds, 0, 0, 0]
        },
        translation: {
          epoch: zhutuiDStartTime,
          cartesian: unBiasedTranslation
        }
      },
      shangmianji: {
        translation: {
          epoch: xin01jiStartTime,
          cartesian: shangmianjiBiasedTranslation
        }
      }
    }

    return Transformations
  }

  static J2000toFIXED(time, pointInInertial) {
    const icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time)
    const pointInFixed = new Cesium.Cartesian3()
    if (Cesium.defined(icrfToFixed)) {
      Cesium.Matrix3.multiplyByVector(icrfToFixed, pointInInertial, pointInFixed)
    }
    return pointInFixed
  }

  static FIXEDtoJ2000(time, pointInFIXED) {
    const FixedToicrf = Cesium.Transforms.computeFixedToIcrfMatrix(time)
    const pointInInertial = new Cesium.Cartesian3()
    if (Cesium.defined(FixedToicrf)) {
      Cesium.Matrix3.multiplyByVector(FixedToicrf, pointInFIXED, pointInInertial)
    }
    return pointInInertial
  }

  static HEU_DeleteListener(viewer) {
    const deletelistener = viewer.scene.preUpdate._listeners.filter(function (item) {
      return item.name === "addViewObsEvent"
    })[0]
    viewer.scene.preUpdate.removeEventListener(deletelistener, "addEvent")
  }
}

export default CZML_GENERALTOOLS_CLASS
